package com.mg.pluginwebservice;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.mg.model.*;
import com.mg.pluginexample2.Model2;
import com.mg.pluginexample2.ModuleBase;
import com.mg.pluginwebservice.util.HttpRequestUtils;

/**
 * 如果输入端或输出端可动态增删端口，需要派生端口类，否则Undo可能出错。
 */


public class CalculateSuitabilityDegreeModel extends ModuleBase {
    public CalculateSuitabilityDegreeModel(int nID) {
        super(nID);
        m_alOutputPort.add(new Port(this, Port.Type.Unknown));//输出字符串
        m_strHost = "http://172.24.176.171:8088/GWFS_GridDataShare/dataShare/getStationDataInGridWithStationType";
        m_sdfYMD = new SimpleDateFormat("yyyy-MM-dd");
        m_sdfYMDHMS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        m_strForecastValidStart = "3";
        m_strForecastValidEnd = "192";
        m_strDayFormatType = "0";
    }

    public String GetGroupName() {
        return "WebHTTP";
    }

    public String GetName() {
        return "重庆农气适宜度计算";
    }

    public String GetDescription() {
        return "";
    }

    public boolean OnAttach(Port portFrom, Port portTo) {
        try {
            int i = FindPort(portFrom, false);
            if (i != -1)
                return true;
            i = FindPort(portTo, true);
            if (i == -1)
                return false;
            if (portFrom.GetType() != portTo.GetType())
                return false;
            ArrayList<Param> alParam = new ArrayList<Param>();
            portFrom.GetModule().GetOutputParam(portFrom, alParam);
            if (alParam.size() < 2)
                return false;

        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }

        return true;
    }

    public boolean OnDetach(Port portFrom, Port portTo) {
        if (!super.OnDetach(portFrom, portTo))
            return false;
        try {
            int i = FindPort(portTo, true);
            if (i == -1)
                return true;
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    //用于 参数->XML 等
    public int GetParam(ArrayList<Param> alParam) {
        try {
            super.GetParam(alParam);

            Model2 model = ((Model2) m_model);

            alParam.add(new Param("Host", m_strHost, "地址", "xxx.xxx.xxx.xxx:xxxx", "WebService", Param.EditType.Default));
            alParam.add(new Param("UserID", m_strUserName, "用户名", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("PassWord", m_strPassword, "密码", "", "WebService", Param.EditType.Default));

            alParam.add(new Param("Origin", m_strOrigin, "场信息", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("Sequence", m_strSequenceValue, "时次", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("ForecastDate", m_strDate, "预报时间", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("ForecastFileVersion", m_strForecastFileVersion, "文件版本", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("StationType", m_strStationType, "站点类型", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("CalcDay", m_strCalcDay, "统计天数", "", "WebService", Param.EditType.Default));
            alParam.add(new Param("DayFormat", m_strDayFormatType, "时间偏移（天）", "", "WebService", Param.EditType.Default));

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return alParam.size();
    }

    public boolean OnParamChanged(ArrayList<Param> alParam, int nIndex, Object objValue) {
        return super.OnParamChanged(alParam, nIndex, objValue);
    }

    //用于 XML->参数 等
    public int SetParam(final ArrayList<Param> alParam) {
        int i = super.SetParam(alParam);
        try {
            m_strHost = (String) alParam.get(i++).m_objValue;
            m_strUserName = (String) alParam.get(i++).m_objValue;
            m_strPassword = (String) alParam.get(i++).m_objValue;
            m_strOrigin = (String) alParam.get(i++).m_objValue;
            m_strSequenceValue = (String) alParam.get(i++).m_objValue;
            m_strDate = (String) alParam.get(i++).m_objValue;

            m_strForecastFileVersion = (String) alParam.get(i++).m_objValue;
            m_strStationType = (String) alParam.get(i++).m_objValue;
            m_strCalcDay = (String) alParam.get(i++).m_objValue;
            m_strDayFormatType = (String) alParam.get(i++).m_objValue;

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return i;
    }

    @SuppressWarnings("static-access")
    public boolean Execute() {

        try {
            calcRealDate();
        } catch (ParseException e) {
            return false;
        }

        m_strForecastValidEnd = String.valueOf(Integer.parseInt(m_strCalcDay) * 24 + 24);
        boolean flag = true;
        JSONObject param = new JSONObject();
        param.put("origin", m_strOrigin);
        param.put("sequenceValue", m_strSequenceValue);
        param.put("forecastDate", m_strForecastDate);
        param.put("forecastValidStart", m_strForecastValidStart);
        param.put("forecastValidEnd", m_strForecastValidEnd);
        param.put("forecastFileVersion", m_strForecastFileVersion);
        param.put("userName", m_strUserName);
        param.put("password", m_strPassword);
        param.put("stationType", m_strStationType);
        param.put("element", "TMP,2T");
        m_model.OutputLog(Model.LogLevel.Info, param.toJSONString());
        JSONObject dataTMP = executeMethod(m_strHost, param);
        param.put("element", "ER12");
        m_model.OutputLog(Model.LogLevel.Info, param.toJSONString());
        JSONObject dataER12 = executeMethod(m_strHost, param);
        try {
            assistData(dataTMP, dataER12);
        } catch (ParseException e) {
            flag = false;
        }
        OnParamChanged();
        m_model.OutputLog(Model.LogLevel.Info, "Result Size:" + m_listCSV.size());
        return flag;
    }

    private void calcRealDate() throws ParseException {
        String tmpDateStr = m_strDate;
        if("$DataStartTime".equals(m_strDate)){
            tmpDateStr = m_sdfYMD.format(m_model.m_dateDataStart);
        }
        Date tmpDate = m_sdfYMD.parse(tmpDateStr);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(tmpDate);
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + Integer.parseInt(m_strDayFormatType));
        m_strForecastDate = m_sdfYMD.format(calendar.getTime());
    }

    private JSONObject executeMethod(String wsdlUrl, JSONObject param) {
        JSONObject data = null;
        try {
            data = HttpRequestUtils.httpPost(wsdlUrl, param, HttpRequestUtils.CONTENT_TYPE_JSON);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    private void assistData(JSONObject dataTMP, JSONObject dataER12) throws ParseException {
        JSONObject log = new JSONObject();
        m_listCSV.clear();
        String head = "StationNum,x,y,Time,Data";
        String type = "String,Double,Double,String,Double";
        m_listCSV.add(head);
        m_listCSV.add(type);
        if (dataTMP.getInteger("status") != 1 || dataER12.getInteger("status") != 1) {
            return;
        }
        JSONObject tmpParam = dataTMP.getJSONObject("data");
        JSONObject er12Param = dataER12.getJSONObject("data");
        for (String stationNum : tmpParam.keySet()) {
            JSONArray tmp = tmpParam.getJSONObject(stationNum).getJSONArray("TMP");
            JSONArray er12 = er12Param.getJSONObject(stationNum).getJSONArray("ER12");
            JSONArray loc = tmpParam.getJSONObject(stationNum).getJSONArray("Location");

            int level = calcSuitabeLevel(tmp, er12, loc, stationNum, log);


            Date date = m_sdfYMD.parse(m_strForecastDate);
            date.setHours(8);
            String strData = stationNum + "," + loc.getDoubleValue(0) + "," +
                    loc.getDoubleValue(1) + "," + m_sdfYMDHMS.format(date) + "," + level;
            m_listCSV.add(strData);
        }
    }

    private int calcSuitabeLevel(JSONArray tmp, JSONArray er12, JSONArray loc, String stationNum, JSONObject log) {
        int count = er12.size();
        double alti = loc.getDoubleValue(2);

        if (count * 4 != tmp.size()) {
            System.out.println("count:count:");
            return -4;
        }
        double avgTmp = calcAvgTmp(tmp);
        int rainDay = calcRainDay(er12);
        int continuousNoRainDay = calcContinuousNoRainDay(er12);
        String logStr = ",continuousNoRainDay= " + continuousNoRainDay + "avgTmp=" + avgTmp + ",rainDay=" + rainDay + ",alti=" + alti;
        log.put(stationNum, logStr);
//        if (alti >= 800) {
//            return 1;
//        }

        if (avgTmp < 10) {
            return 3;
        }
        if (continuousNoRainDay >= 3 && rainDay < 4) {
            return 7;
        } else if (continuousNoRainDay >= 2 && rainDay <= 4) {
            return 5;
        } else {
            return 3;
        }
    }

    private int calcContinuousNoRainDay(JSONArray er12) {
        int[] rainDay = new int[er12.size() / 2 - 1];
        for (int i = 0; i < er12.size() / 2 - 1; i++) {
            boolean sim = ((BigDecimal) er12.get(2 * i + 1)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 1)).doubleValue() < 9999;
            boolean dou = ((BigDecimal) er12.get(2 * i + 2)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 2)).doubleValue() < 9999;
            if (sim || dou) {
                rainDay[i] = 1;
            } else {
                rainDay[i] = 0;
            }
        }
        int max = 0;
        int tmp = 0;
        for (int day : rainDay) {
            if (day > 0) {
                tmp++;
            } else {
                tmp = 0;
            }
            max = (max - tmp) > 0 ? max : tmp;
        }
        return max;
    }

    private int calcRainDay(JSONArray er12) {
        int day = 0;
        for (int i = 0; i < er12.size() / 2 - 1; i++) {
            boolean sim = ((BigDecimal) er12.get(2 * i + 1)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 1)).doubleValue() < 9999;
            boolean dou = ((BigDecimal) er12.get(2 * i + 2)).doubleValue() > 0 && ((BigDecimal) er12.get(2 * i + 2)).doubleValue() < 9999;
            if (sim || dou) {
                day++;
            }
        }
        return day;
    }

    private double calcAvgTmp(JSONArray tmp) {
        int calcTmpDay = tmp.size() > 48 ? 48 : tmp.size();
        double totalAvg = 0;
        int calCount = 0;
        for (int i = 5; i < calcTmpDay - 4; i += 2) {
            totalAvg += ((BigDecimal) tmp.get(i)).doubleValue();
            calCount++;
        }
        return totalAvg / calCount;
    }

    public int GetOutputParam(Port port, ArrayList<Param> alParam) {
        int i = FindPort(port, false);
        if (i == -1)
            return 0;
        alParam.add(new Param("ResultString", m_listCSV));
        return alParam.size();
    }

    List<String> m_listCSV = new ArrayList<String>();

    String m_strHost;
    String m_strUserName;
    String m_strPassword;
    String m_strOrigin;
    String m_strSequenceValue;
    String m_strForecastDate;
    String m_strDate;
    String m_strForecastValidStart;
    String m_strForecastValidEnd;
    String m_strForecastFileVersion;
    String m_strStationType;
    String m_strCalcDay;
    String m_strDayFormatType;

    SimpleDateFormat m_sdfYMD;
    SimpleDateFormat m_sdfYMDHMS;
}


